package tuanda.soict.firstsun.PresentationPackage;

import java.util.ArrayList;
import java.util.Random;

import tuanda.soict.firstsun.AbilityPackage.Ability;
import tuanda.soict.firstsun.BuildingPackage.Army_Building;
import tuanda.soict.firstsun.BuildingPackage.Building;
import tuanda.soict.firstsun.BuildingPackage.HQ_Building;
import tuanda.soict.firstsun.DataPackage.AbilityList;
import tuanda.soict.firstsun.DataPackage.CommonConstants;
import tuanda.soict.firstsun.DataPackage.GroupDataStructure;
import tuanda.soict.firstsun.LogicPackage.AI_Part;
import tuanda.soict.firstsun.LogicPackage.Army;
import tuanda.soict.firstsun.LogicPackage.AttackSet;
import tuanda.soict.firstsun.LogicPackage.BattleMap;
import tuanda.soict.firstsun.LogicPackage.CompleteActionSet;
import tuanda.soict.firstsun.LogicPackage.Coordinate;
import tuanda.soict.firstsun.LogicPackage.MovementSet;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class TiledMapRendererScreen extends AbstractTiledMapRendererScreen
		implements GeneralConstants, CommonConstants, AbilityList {

	private ScenarioInitializer scenarioInitializer;
	private DrawHelper drawHelper;
	private SpriteBatch spriteBatch;
	private ControlMenu controlMenu;
	private AI_Part ai_Part;
	private BattleMap map;
	private Army currentActingArmy;
	private int currentIndex;
	private CompleteActionSet completeActionSet;
	private boolean isBuyCompleted;

	public TiledMapRendererScreen(Object[] inputData, TalesOfTroubadour game) {
		super(inputData, game);
		scenarioInitializer = new ScenarioInitializer();
		controlMenu = new ControlMenu(this);
	}

	public void processTouchEvent() {
		int inputX = Gdx.input.getX();
		int inputY = Gdx.input.getY();
		if (Gdx.input.justTouched()) {
			coor = convertCoordinate(lastTouchedX, lastTouchedY);
			if (Math.abs(lastTouchedX - inputX) < tapWidth
					&& Math.abs(lastTouchedY - inputY) < tapHeight) {
				if (inputY < (screenHeight - 74)) {
					if (screenState != MOVING_SCREEN
							&& screenState != ATTACKING_SCREEN
							&& screenState != ATTACK_ANIMATION_SCREEN
							&& screenState != OCCUPYING_SCREEN
							&& screenState != OCCUPY_ANIMATION_SCREEN
							&& screenState != ABILITY_ACTING_SCREEN
							&& screenState != ABILITY_ANIMATION_SCREEN) {
						prevX = currentX;
						prevY = currentY;
						currentX = coor.getLocationX() >> 6;
						currentY = (((rows) << 6) - coor.getLocationY()) >> 6;
						processInputEvent();
					}
				}
			}
			lastTouchedX = inputX;
			lastTouchedY = inputY;
		} else if (Gdx.input.isTouched()) {
			camera.position.x += lastTouchedX - inputX;
			camera.position.y += inputY - lastTouchedY;
			lastTouchedX = inputX;
			lastTouchedY = inputY;
		}
	}

	@Override
	public void render(float delta) {
		stage.act(delta);
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

		switch (generalState) {
		case DEFAULT: {
			processTouchEvent();
			checkCameraBoundaries();

			camera.update();
			
			tiledMapHelper.render();

			spriteBatch.begin();
			drawHelper.drawSprites();
			drawHelper.drawMenu();
			spriteBatch.end();
			stage.draw();

			controlFramePerSecond();
			break;
		}
		case BUY_SCREEN: {
			spriteBatch.begin();
			drawHelper.drawMenu();
			spriteBatch.end();
			stage.draw();
			controlFramePerSecond();
			break;
		}
		case COMPUTER_CONTROL: {
			switch (screenState) {
			case DEFAULT: {
				if (isBuyCompleted == true) {
					setScreenState(CALCULATING);
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
					}
				} else {
					setScreenState(CALCULATING_BUY);
				}
				break;
			}
			case CALCULATING: {
				Army[] armies = ai_Part.getGroup(ai_Part.getCurrentTurn())
						.getArmy();
				for (int i = currentIndex; i < armies.length; i++) {
					if (armies[i] != null) {
						if (armies[i].isMoveLeft() == true
								&& armies[i].isActionLeft() == true) {
							completeActionSet = ai_Part.generateSingleMove(
									armies[i], 0);
							currentActingArmy = armies[i];
							controlMenu.setArmy(currentActingArmy);
							currentIndex += 1;
							setScreenState(processComputerActionSet());
							completeActionSet = null;
							break;
						} else {
							currentIndex += 1;
						}
					} else {
						currentIndex += 1;
					}
				}
				if (currentIndex >= DEFAULT_MAX_ARMY_PER_GROUP) {
					currentIndex = 0;
					setGeneralState(DEFAULT);
					setScreenState(DEFAULT);
					ai_Part.nextTurn();
					controlMenu.createMenuScreen(true);
				}
				break;
			}
			case CALCULATING_BUY: {
				if (ai_Part.prepareGenerateNewArmy(ai_Part.getGroup(ai_Part
						.getCurrentTurn())) == true) {
					Army_Building army_Building = ai_Part
							.getChosenArmyBuilding();
					int building_X = army_Building.getLocationX();
					int building_Y = army_Building.getLocationY();
					Army temp = map.getArmy(building_X, building_Y);
					if (temp == null) {
						setScreenState(BUY);
					} else {
						if (temp.isActionLeft() == true
								&& temp.isMoveLeft() == true) {
							completeActionSet = ai_Part.generateSingleMove(
									temp, 0);
							currentActingArmy = temp;
							controlMenu.setArmy(currentActingArmy);
							setScreenState(processComputerActionSet());
							completeActionSet = null;
						} else {
							if (ai_Part.isBuyCompleted() == true) {
								isBuyCompleted = true;
								setScreenState(CALCULATING);
							} else {
								ai_Part.increaseCurrentIndex();
							}
						}
					}
				} else {
					isBuyCompleted = true;
					setScreenState(CALCULATING);
				}
			}
				break;
			case BUY:
				ai_Part.addNewArmy(ai_Part.getChosenArmy(), ai_Part
						.getCurrentTurn(), ai_Part.getChosenArmyBuilding()
						.getLocationX(), ai_Part.getChosenArmyBuilding()
						.getLocationY(), (new Random())
						.nextInt(NUMBER_ATTRIBUTE));
				setScreenState(CALCULATING_BUY);
				break;
			default: {
				checkCameraBoundaries();

				camera.update();
				tiledMapHelper.render();

				spriteBatch.begin();
				drawHelper.drawSprites();
				drawHelper.drawMenu();
				spriteBatch.end();
				controlMenu.createMenuScreen(false);
				stage.draw();

				controlFramePerSecond();
			}
				break;
			}
			break;
		}
		}
	}

	@Override
	public void resize(int width, int height) {
		super.resize(width, height);
		loadData();
		lastRender = now = System.nanoTime();
		drawHelper = new DrawHelper(width, height, scenarioInitializer, rows,
				cols, this);
		spriteBatch = drawHelper.getSpriteBatch();
		controlMenu.setAiPart(ai_Part);
		if (ai_Part.getPlayerType(ai_Part.getCurrentTurn()) == HUMAN_PLAYER) {
			controlMenu.createMenuScreen(true);
			setScreenState(DEFAULT);
			setGeneralState(DEFAULT);
		} else {
			setScreenState(DEFAULT);
			setGeneralState(COMPUTER_CONTROL);
			controlMenu.createMenuScreen(false);
		}
	}

	@Override
	public void dispose() {
		super.dispose();
		spriteBatch.dispose();
		drawHelper.clearResources();
	}

	public void loadData() {
		scenarioInitializer.parseTileSetData((String) data[4]);
		ai_Part = scenarioInitializer
				.parseScenarioData((String) data[2], tiledMapHelper,
						(Boolean) data[3], (GroupDataStructure) data[5]);
		scenarioInitializer.createCreatureTile();
		map = ai_Part.getBattleMap();
		rows = map.getNumberOfRow();
		cols = map.getNumberOfColumn();

	}

	public void resetAnimation() {
		drawHelper.resetAnimation();
	}

	public ScenarioInitializer getScenarioInitializer() {
		return this.scenarioInitializer;
	}

	public AI_Part getAi_Part() {
		return this.ai_Part;
	}

	public ControlMenu getControlMenu() {
		return this.controlMenu;
	}

	public BattleMap getMap() {
		return this.map;
	}

	public void setDestination(int x, int y) {
		drawHelper.setDestinationX(x);
		drawHelper.setDestinationY(y);
	}

	public DrawHelper getDrawSpritesHelper() {
		return this.drawHelper;
	}

	public Army getCurrentActingArmy() {
		return currentActingArmy;
	}

	public void setCurrentActingArmy(Army currentArmy) {
		this.currentActingArmy = currentArmy;
	}

	public CompleteActionSet getCompleteActionSet() {
		return completeActionSet;
	}

	public void setCompleteActionSet(CompleteActionSet completeSet) {
		this.completeActionSet = completeSet;
	}

	public int getCurrentIndex() {
		return currentIndex;
	}

	public void setCurrentIndex(int index) {
		this.currentIndex = index;
	}

	public boolean isBuyCompleted() {
		return isBuyCompleted;
	}

	public void setBuyCompleted(boolean isCompleted) {
		this.isBuyCompleted = isCompleted;
	}

	public void processInputEvent() {
		switch (screenState) {
		case DEFAULT: {
			if (map.getArmy(currentX, currentY) != null) {
				Army arm = map.getArmy(currentX, currentY);
				if (arm.getGroupID() == ai_Part.getCurrentTurn()) {
					controlMenu.setArmy(arm);
					controlMenu.createArmyControlScreen();
				} else {
					if (map.getBuilding(currentX, currentY) != null) {
						controlMenu.createArmyControl(arm, true);
					} else {
						controlMenu.createArmyControl(arm, false);
					}
				}
			} else if (map.getBuilding(currentX, currentY) != null) {
				controlMenu.createBuildingControl(
						map.getBuilding(currentX, currentY), false);
			} else {
				controlMenu.createEnvironmentInfo(map.getEnvironment(currentX,
						currentY));
			}
		}
			break;
		case MOVE_SCREEN: {
			if (map.getMovementSet(currentX, currentY) != null) {
				setScreenState(MOVE_TARGET_SCREEN);
				resetAnimation();
				drawHelper.setDestinationX(currentX);
				drawHelper.setDestinationY(currentY);
				controlMenu
						.createConfirmScreen("Are you sure you want to move ?");
			}
		}
			break;
		case MOVE_TARGET_SCREEN: {
			controlMenu.createMenuScreen(true);
			drawHelper.setDestinationX(currentX);
			drawHelper.setDestinationY(currentY);
			if (map.getMovementSet(currentX, currentY) != null) {
				if (prevX == currentX && prevY == currentY) {
					setScreenState(MOVING_SCREEN);
					resetAnimation();
					controlMenu.createMenuScreen(true);
				}
			} else {
				setScreenState(MOVE_SCREEN);
				resetAnimation();
				controlMenu.createMoveScreen(controlMenu.getArmy());
			}
		}
			break;
		case ATTACK_SCREEN: {
			ArrayList<Coordinate> set = drawHelper.getEnemyPosition();
			for (Coordinate coor : set) {
				if (coor.getLocationX() == currentX
						&& coor.getLocationY() == currentY) {
					setScreenState(ATTACK_TARGET_SCREEN);
					resetAnimation();
					controlMenu
							.createConfirmScreen("Are you sure you want to attack ?");
				}
			}
		}
			break;
		case ATTACK_TARGET_SCREEN: {
			controlMenu
					.createConfirmScreen("Are you sure you want to attack ?");
			MovementSet attackSet = drawHelper.getAttackSet();
			if (attackSet != null) {
				ArrayList<AttackSet> temp = attackSet.getAttackSet();
				if (temp.size() > 0) {
					if (prevX == currentX && prevY == currentY) {
						controlMenu.createMenuScreen(true);
						setScreenState(ATTACKING_SCREEN);
						resetAnimation();
					}
				}
			}
		}
			break;
		case OCCUPY_SCREEN: {
			ArrayList<Coordinate> set = drawHelper.getEnemyPosition();
			for (Coordinate coor : set) {
				if (coor.getLocationX() == currentX
						&& coor.getLocationY() == currentY) {
					setScreenState(OCCUPY_TARGET_SCREEN);
					resetAnimation();
					controlMenu
							.createConfirmScreen("Are you sure you want to occupy ?");
				}
			}
		}
			break;
		case OCCUPY_TARGET_SCREEN: {
			controlMenu
					.createConfirmScreen("Are you sure you want to occupy ?");
			Building enemyBuilding = map.getBuilding(currentX, currentY);
			Army arm = controlMenu.getArmy();

			if (enemyBuilding != null) {
				if (ai_Part.isInSameSide(enemyBuilding.getGroupID(),
						arm.getGroupID()) == false) {
					if (prevX == currentX && prevY == currentY) {
						setScreenState(OCCUPYING_SCREEN);
						controlMenu.createMenuScreen(true);
						resetAnimation();
					}
				} else if (enemyBuilding.getBuildingType() == HEAD_QUARTER_TYPE) {
					if (((HQ_Building) enemyBuilding).getTurnsBeforeLost() != MANY_TURNS) {
						setScreenState(OCCUPYING_SCREEN);
						controlMenu.createMenuScreen(true);
						resetAnimation();
					}
				} else {
					setScreenState(OCCUPY_SCREEN);
					controlMenu.createOccupyScreen(arm);
				}
			} else {
				setScreenState(OCCUPY_SCREEN);
				controlMenu.createOccupyScreen(arm);
			}
		}
			break;
		case ABILITY_SCREEN: {
			ArrayList<Coordinate> set = drawHelper.getEnemyPosition();
			for (Coordinate coor : set) {
				if (coor.getLocationX() == currentX
						&& coor.getLocationY() == currentY) {
					setScreenState(ABILITY_TARGET_SCREEN);
					resetAnimation();
					controlMenu
							.createConfirmScreen("Are you sure you want to use this skill ?");
				}
			}
		}
			break;
		case ABILITY_TARGET_SCREEN: {
			controlMenu
					.createConfirmScreen("Are you sure you want to use this skill ?");
			MovementSet attackSet = drawHelper.getAttackSet();
			if (attackSet != null) {
				ArrayList<AttackSet> temp = attackSet.getAttackSet();
				if (temp.size() > 0) {
					if (prevX == currentX && prevY == currentY) {
						setScreenState(ABILITY_ACTING_SCREEN);
						controlMenu.createMenuScreen(true);
						resetAnimation();
					}
				}
			}
		}
			break;
		}
	}

	public int processComputerActionSet() {
		Coordinate currentPosition = completeActionSet.getCurrentPosition();
		Coordinate destination = completeActionSet.getDestination();
		Ability action = completeActionSet.getAction();
		ArrayList<Coordinate> path = completeActionSet.getMovementPath();

		int destX = destination.getLocationX();
		int destY = destination.getLocationY();

		resetAnimation();

		if (action == null) {
			Coordinate midPoint = currentPosition.findMidPoint(destination);
			camera.position.x = (midPoint.getLocationX() << 6);
			camera.position.y = ((rows - midPoint.getLocationY() - 1) << 6);

			drawHelper.setDestinationX(destX);
			drawHelper.setDestinationY(destY);
			drawHelper.setMovementPath(path);
			drawHelper.initializeMovePath();
			return MOVING_SCREEN;
		} else {
			Coordinate target = action.getTarget();
			currentX = target.getLocationX();
			currentY = target.getLocationY();

			Coordinate midPoint = currentPosition.findMidPoint(target);
			camera.position.x = (midPoint.getLocationX() << 6);
			camera.position.y = ((rows - midPoint.getLocationY() - 1) << 6);

			controlMenu.setAbility(null);

			switch (action.getID()) {
			case ATTACK: {

				int range = currentActingArmy.getAttackRange();
				if ((Math.abs(currentX - currentActingArmy.getLocationX()) + Math
						.abs(currentY - currentActingArmy.getLocationY())) > range) {
					MovementSet attackSet = new MovementSet(destX, destY);
					attackSet.addAttackItem(currentX, currentY);
					drawHelper.setAttackSet(attackSet);

					drawHelper.setDestinationX(destX);
					drawHelper.setDestinationY(destY);
					drawHelper.setMovementPath(path);
					drawHelper.initializeMovePath();
				} else {
					drawHelper
							.setDestinationX(currentActingArmy.getLocationX());
					drawHelper
							.setDestinationY(currentActingArmy.getLocationY());
				}
				return ATTACKING_SCREEN;
			}
			case OCCUPY: {
				if (currentX != currentActingArmy.getLocationX()
						|| currentY != currentActingArmy.getLocationY()) {
					drawHelper.setDestinationX(destX);
					drawHelper.setDestinationY(destY);
					drawHelper.setMovementPath(path);
					drawHelper.initializeMovePath();
				} else {
					drawHelper
							.setDestinationX(currentActingArmy.getLocationX());
					drawHelper
							.setDestinationY(currentActingArmy.getLocationY());
				}
				return OCCUPYING_SCREEN;
			}
			default: {
				int range = action.getAbilityRange();
				controlMenu.setAbility(action);
				if ((Math.abs(currentX - currentActingArmy.getLocationX()) + Math
						.abs(currentY - currentActingArmy.getLocationY())) > range) {
					MovementSet abilSet = new MovementSet(destX, destY);
					abilSet.addAttackItem(currentX, currentY);
					drawHelper.setAttackSet(abilSet);

					drawHelper.setDestinationX(destX);
					drawHelper.setDestinationY(destY);
					drawHelper.setMovementPath(path);
					drawHelper.initializeMovePath();
				} else {
					drawHelper
							.setDestinationX(currentActingArmy.getLocationX());
					drawHelper
							.setDestinationY(currentActingArmy.getLocationY());
				}
				return ABILITY_ACTING_SCREEN;
			}
			}
		}
	}
}